package edu.sysu.demo.petstore.dog.user;

import edu.sysu.demo.petstore.dog.data.dao.RoleDao;
import edu.sysu.demo.petstore.dog.data.dao.UserDao;
import edu.sysu.demo.petstore.dog.data.entity.Role;
import edu.sysu.demo.petstore.dog.data.entity.User;
import java.time.LocalDate;
import java.util.Collections;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author lijinting01
 */
@Component
@Transactional
public class UserService implements UserDetailsService, RegisterService, LoginService {


  private static final String ROLE_USERS = "users";

  private final RoleDao roleDao;

  private final UserDao userDao;

  private final PasswordEncoder passwordEncoder;

  @Autowired
  public UserService(RoleDao roleDao, UserDao userDao, PasswordEncoder passwordEncoder) {
    this.roleDao = roleDao;
    this.userDao = userDao;
    this.passwordEncoder = passwordEncoder;
  }

  @Override
  public UserDetails loadUserByUsername(String username) {
    User user = Optional.ofNullable(userDao.findByUsername(username))
        .orElseThrow(() -> new UsernameNotFoundException(username));
    return new UserDetailsAdapter(user);
  }

  @Override
  public User register(String username, String password) {
    Optional.ofNullable(userDao.findByUsername(username))
        .ifPresent(user -> {
          throw new DuplicateUsernameException();
        });

    Role users = roleDao.findByName(ROLE_USERS);

    User user = User.builder()
        .enabled(true)
        .locked(false)
        .expireAt(LocalDate.now().plusYears(50))
        .password(passwordEncoder.encode(password))
        .username(username)
        .roles(Collections.singleton(users))
        .build();

    return userDao.save(user);
  }

  @Override
  public boolean login(String username, String password) {
    UserDetails user = loadUserByUsername(username);
    String storedPassword = user.getPassword();
    return user.isEnabled()
        && user.isAccountNonLocked()
        && user.isAccountNonExpired()
        && passwordEncoder.matches(password, storedPassword);

  }
}
